#include "SceneManager.h"
#include "FileManager.h"
#include <stdio.h>
#include "ScreenResolution.h"

SceneManager* SceneManager::s_instance = NULL;
Shader *shaderSelection = NULL;
CameraLookat *cameraLookat = NULL;
extern Object *woman2;

union ColorRGBA
{
	int colorValue;
	struct
	{
		unsigned char r, g, b, a;
	};
};

ColorRGBA colorI;

SceneManager::SceneManager(void)
{
}

SceneManager::~SceneManager(void)
{
	for (int i = 0; i < m_numOfObject; i++)
	{
		SAFE_DEL(m_object[i]);
	}

	SAFE_DEL(m_object);

	SAFE_DEL(m_camera);

	SAFE_DEL(m_cameraLookat);
}

void SceneManager::Init(const char *fileName)
{
	ResourceManager *resourceManager = ResourceManager::GetInstance();
	FileManager *fileManager = FileManager::GetInstance();

	FILE *pFile = fileManager->Open(fileName, "r");

	if (pFile == NULL)
	{
		LOGI("Cannot open file %s.\n", fileName);
		return;
	}

	else
	{
		char idObject[MAX_10];
		char idModel[MAX_10];
		char idTexture[MAX_10];
		char idShader[MAX_10];
		Vector3 position;
		Vector3 rotate;
		Vector3 scale;

		fscanf(pFile, "#Objects: %d\n", &m_numOfObject);

		m_object = new Object*[m_numOfObject];

		for (int i = 0; i < m_numOfObject; i++)
		{
			fscanf(pFile, "ID: %s\n", idObject);
			fscanf(pFile, "Model: %s\n", idModel);
			fscanf(pFile, "Texture: %s\n", idTexture);
			fscanf(pFile, "Shader: %s\n", idShader);
			fscanf(pFile, "Position: %f, %f, %f\n", &position.x, &position.y, &position.z);
			fscanf(pFile, "Rotate: %f, %f, %f\n", &rotate.x, &rotate.y, &rotate.z);
			fscanf(pFile, "Scale: %f, %f, %f\n", &scale.x, &scale.y, &scale.z);

			m_object[i] = new Object();
			m_object[i]->Init(idObject, position, rotate, scale,
				resourceManager->GetTextureById(idTexture),
				resourceManager->GetModelById(idModel),
				resourceManager->GetShaderById(idShader));
		}
		
		float nearPlane, farPlane, fovY, speed;
		fscanf(pFile, "#Camera\n");
		fscanf(pFile, "Near: %f\n", &nearPlane);
		fscanf(pFile, "Far: %f\n", &farPlane);
		fscanf(pFile, "FOVY: %f\n", &fovY);
		fscanf(pFile, "Speed: %f\n", &speed);

		fovY = fovY * PI / 180;

		m_camera = new Camera();

		m_camera->Init(fovY, ScreenResolution::GetInstance()->GetScreenRatio(), nearPlane, farPlane, speed);
	}

	fclose(pFile);
	shaderSelection = resourceManager->GetShaderById("Selection");

	cameraLookat = new CameraLookat();
	m_cameraLookat = cameraLookat;
	m_cameraLookat->m_target = m_object[1]->m_position;
}

void SceneManager::Update()
{
	m_cameraLookat->Update();

	for (int i = 0; i < m_numOfObject; i++)
	{
		m_object[i]->Update();
	}
}

void SceneManager::DrawSelection()
{
	ResourceManager *resourceManager = ResourceManager::GetInstance();

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//Matrix viewProjectMatrix = m_camera->CalculateViewProjectMatrix();
	Matrix viewProjectMatrix = m_cameraLookat->CalculateViewProjectMatrix();

	Shader *shader = NULL;
	for (int i = 0; i < m_numOfObject; i++)
	{
		colorI.colorValue = i;

		// back up Object's shader
		shader = m_object[i]->m_shader;

		// use shader "Selection"
		m_object[i]->m_shader = shaderSelection;

		//m_object[i]->m_color = Vector4(i * 0.1f, 0.0f, 0.0f, i * 0.1f);
		m_object[i]->m_color = Vector4((float) colorI.r / 0xFF, (float) colorI.g / 0xFF, (float) colorI.b / 0xFF, (float) colorI.a / 0xFF);
		
		m_object[i]->Draw(viewProjectMatrix);

		// restore Object's shader
		m_object[i]->m_shader = shader;
	}
}

void SceneManager::Draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	Matrix viewProjectMatrix = m_cameraLookat->CalculateViewProjectMatrix();

	for (int i = 0; i < m_numOfObject; i++)
	{
		m_object[i]->Draw(viewProjectMatrix);
	}
}

SceneManager* SceneManager::GetInstance()
{
	if (s_instance == NULL)
	{
		s_instance = new SceneManager();
	}
	return s_instance;
}

void SceneManager::Destroy()
{
	if (s_instance != NULL)
	{
		SAFE_DEL(s_instance);
	}
}

Camera* SceneManager::GetCameraPointer()
{
	return m_camera;
}

Object* SceneManager::GetObjectIdByIndex(int index)
{
	if (index >= 0 && index < m_numOfObject)
	{
		LOGI("Object %s\n", m_object[index]->GetID());
		return m_object[index];
	}
	
	else
	{
		LOGI("Object undefined\n");
		return NULL;
	}
}